home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
IRIS Performer 2.2 Friends Demo
/
SGI IRIS Performer 2.2 Friends Demo.iso
/
friends
/
openworlds
/
tix
/
Balloon.tcl.bak
< prev
next >
Wrap
Text File
|
1997-11-22
|
15KB
|
681 lines
# tixBalloon -
#
# The help widget. It provides both "balloon" type of help message
# and "status bar" type of help message. You can use this widget to indicate
# the function of the widgets inside your application.
#
#
tixWidgetClass tixBalloon {
-classname TixBalloon
-superclass tixShell
-method {
bind post unbind
}
-flag {
-installcolormap -initwait -state -statusbar
}
-configspec {
{-installcolormap installColormap InstallColormap false}
{-initwait initWait InitWait 200}
{-state state State both}
{-statusbar statusBar StatusBar {}}
{-cursor cursor Cursur left_ptr}
}
-default {
{*background #ffff60}
{*foreground black}
{*borderWidth 0}
{.borderWidth 1}
{.background black}
}
}
# Class Record
#
set tixBalloon(bals) {}
bind all <Motion> "+tixBalloon::XXMotion %X %Y"
bind all <1> "+tixBalloon::XXButton-1 %X %Y"
bind all <ButtonRelease-1> "+tixBalloon::XXButton-1 %X %Y"
proc tixBalloon:XXMotion {rootX rootY} {
global tixBalloon
foreach w $tixBalloon(bals) {
tixBalloon::XXMotion $w $rootX $rootY
}
}
proc tixBalloon::XXMotion {w rootX rootY} {
upvar #0 $w data
}
set btn_fields {
%% %# %a %b %c %d %f %h %k %m %o %p %s %t %w %x %y %A %B %E %K %N %R %S %T %W %X %Y
}
proc tixBalloon::InitWidgetRec {w} {
upvar #0 $w data
global tixBalloon
tixChainMethod $w InitWidgetRec
set data(popped) 0
set data(fakeLeave) 0
set data(statusSet) 0
set data(serial) 0
set data(fakeEnter) 0
set data(curWidget) {}
lappend tixBalloon(bals) $w
}
proc tixBalloon::ConstructWidget {w} {
upvar #0 $w data
tixChainMethod $w ConstructWidget
wm overrideredirect $w 1
wm withdraw $w
# Frame 1 : arrow
frame $w.f1 -bd 0
set data(w:label) [label $w.f1.lab -bd 0 -relief flat \
-bitmap [tix getbitmap balArrow]]
pack $data(w:label) -side left -padx 1 -pady 1
# Frame 2 : Message
frame $w.f2 -bd 0
set data(w:message) [message $w.f2.message -padx 0 -pady 0 -bd 0]
pack $data(w:message) -side left -expand yes -fill both -padx 10 -pady 1
# Pack all
pack $w.f1 -fill both
pack $w.f2 -fill both
}
#----------------------------------------------------------------------
# Config:
#----------------------------------------------------------------------
proc tixBalloon::config-state {w value} {
upvar #0 $w data
case $value {
{none balloon status both} {}
default {
error "invalid value $value, must be none, balloon, status, or both"
}
}
}
#----------------------------------------------------------------------
# PrivateMethods:
#----------------------------------------------------------------------
proc tixBalloon::ClientDestroy {w client} {
upvar #0 $w data
if {$data(curWidget) == $client} {
tixBalloon::Popdown $w
}
# Maybe thses have already been unset by the Destroy method
#
catch {unset data(m:$client)}
catch {unset data(s:$client)}
}
# Handle the mouse pointer entering the client widget
#
proc tixBalloon::Enter {w client} {
upvar #0 $w data
if {$data(fakeEnter) > 0} {
# The mouse pointer just left either the balloon window or the
# client window: do nothing; otherwise the balloon will flash
#
set data(fakeEnter) 0
return
}
if {$data(-state) != "none"} {
set data(popped) 0
set data(statusSet) 0
set data(curWidget) $client
incr data(serial)
after $data(-initwait) tixBalloon::Activate $w $data(serial)
}
}
proc tixBalloon::post {w client} {
upvar #0 $w data
if {![info exists data(m:$client)]} {
return
}
tixBalloon::Enter $w $client
incr data(fakeEnter)
}
proc tixBalloon::Within {wid rootX rootY} {
set rx1 [winfo rootx $wid]
set ry1 [winfo rooty $wid]
set rw [winfo width $wid]
set rh [winfo height $wid]
set rx2 [expr $rx1+$rw]
set ry2 [expr $ry1+$rh]
if {$rootX >= $rx1 && $rootX < $rx2 && $rootY >= $ry1 && $rootY < $ry2} {
return 1
} else {
return 0
}
}
proc tixBalloon::Leave [concat w $btn_fields] {
upvar #0 $w data
return
set rootX [set %X]
set rootY [set %Y]
if {$data(curWidget) == ""} {
return
}
if {$data(fakeLeave) == 1} {
set data(fakeLeave) 0
return
}
set cw [winfo containing $rootX $rootY]
set mask [tixBalloon::GetMask $w $data(curWidget)]
if [tixBalloon::Within $w $rootX $rootY] {
# It is safe to do this because we know the balloon is always on top
#
set data(fakeEnter) 1
return
}
if [tixBalloon::Within $data(curWidget) $rootX $rootY] {
return
}
if {$cw == $mask} {
set data(fakeEnter) 1
return
}
puts LLLLLL
if {$data(popped) == 1 || $data(statusSet) == 1} {
set data(fakeEnter) 0
tixBalloon::Popdown $w
} else {
# have to make sure that previous popup's are cancelled
# just make sure previous
#
incr data(serial)
}
tixDeleteBindTag $data(curWidget) InterceptLeave
set args {}
global btn_fields
foreach f $btn_fields {
lappend args [set $f]
}
eval tixBalloon::GenerateEvent $w $data(curWidget) <Leave> $args
}
proc tixBalloon::Activate {w serial} {
if {![winfo exists $w]} {
return
}
upvar #0 $w data
if [info exists data(grabbed)] {
return
}
if {![winfo exists $data(curWidget)]} {
return
}
if {$serial != $data(serial)} {
# a new balloon will be activated by the latest call
#
return
}
set mask [tixBalloon::GetMask $w $data(curWidget)]
if {![tixBalloon::IsInClient $w $data(curWidget) $data(curWidget)]} {
return
}
tixBalloon::InterceptLeave $w $data(curWidget)
# Put the inputonly window over the client
#
set tp [winfo toplevel $data(curWidget)]
set x [expr [winfo rootx $data(curWidget)]-[winfo rootx $tp]]
set y [expr [winfo rooty $data(curWidget)]-[winfo rooty $tp]]
set W [winfo width $data(curWidget)]
set H [winfo height $data(curWidget)]
tixMoveResizeWindow $mask $x $y $W $H
tixMapWindow $mask
raise $mask
update
if {$data(-state) == "both" || $data(-state) == "balloon"} {
tixBalloon::Popup $w
}
if {$data(-state) == "both" || $data(-state) == "status"} {
tixBalloon::SetStatus $w
}
}
proc tixBalloon::Popup {w} {
upvar #0 $w data
if [tixGetBoolean -nocomplain $data(-installcolormap)] {
wm colormapwindows [winfo toplevel $data(curWidget)] $w
}
# trick: the following lines allow the balloon window to
# acquire a stable width and height when it is finally
# put on the visible screen
#
set client $data(curWidget)
$data(w:message) config -text $data(m:$client)
wm geometry $w +10000+10000
wm deiconify $w
raise $w
update
# Put it on the visible screen
#
set x [expr [winfo rootx $client]+[winfo width $client]/2]
set y [expr int([winfo rooty $client]+[winfo height $client]/1.3)]
wm geometry $w +$x+$y
set data(popped) 1
after 100 "tixBalloon::Verify $w $data(curWidget)"
}
bind InterceptLeave <Leave> "tixBalloon:InterceptLeaveDone %W; break"
proc tixBalloon::InterceptLeave {w client} {
tixAddBindTag $client InterceptLeave
}
proc tixBalloon:InterceptLeaveDone {client} {
tixDeleteBindTag $client tixAddBindTag
}
# tixBalloon::Verify
# Sometimes we "lose events" when the user moves the mouse pointer
# rapidly. This routine continuously check whether the mouse
# pointer is still in the balloon region. If not, it pops down the
# balloon.
#
proc tixBalloon::Verify {w client} {
upvar #0 $w data
if {![winfo exists $w]} {
return
}
if {!$data(popped)} {
return
}
if {$data(curWidget) != $client} {
return
}
set mask [tixBalloon::GetMask $w $client]
if {![tixBalloon::IsInClient $w $client $mask]} {
tixBalloon::Popdown $w
} else {
after 100 tixBalloon::Verify $w $client
}
}
proc tixBalloon::IsInClient {w client mask} {
upvar #0 $w data
set rootX [winfo pointerx $client]
set rootY [winfo pointery $client]
if {$rootX == -1 || $rootY == -1} {
# mouse pointercursor moved to another screen
return 0
}
set cw [winfo containing $rootX $rootY]
if {[tixBalloon::Within $w $rootX $rootY]} {
# return 1 if mouse pointer position OK
# (still in either client or balloon)
return 1
}
if {$client == $mask} {
if {[string match $mask* $cw]} {
return 1
}
} else {
if {$cw == $mask} {
return 1
}
}
return 0
}
proc tixBalloon::Popdown {w} {
upvar #0 $w data
# Close the balloon
#
wm withdraw $w
# Clear the status bar
#
if {$data(statusSet) == 1} {
tixBalloon::ClearStatus $w
set $data(statusSet) 0
}
# Withdraw the mask window
#
tixUnmapWindow [tixBalloon::GetMask $w $data(curWidget)]
set data(popped) 0
}
proc tixBalloon::SetStatus {w} {
upvar #0 $w data
if {![winfo exists $data(-statusbar)]} {
return
}
if {$data(-statusbar) != {}} {
set vv [$data(-statusbar) cget -textvariable]
if {$vv == ""} {
$data(-statusbar) config -text $data(s:$data(curWidget))
} else {
uplevel #0 set $vv [list $data(s:$data(curWidget))]
}
}
set data(statusSet) 1
}
proc tixBalloon::ClearStatus {w} {
upvar #0 $w data
if {![winfo exists $data(-statusbar)]} {
return
}
# Clear the StatusBar widget
#
if {$data(-statusbar) != {}} {
set vv [$data(-statusbar) cget -textvariable]
if {$vv == ""} {
$data(-statusbar) config -text ""
} else {
uplevel #0 set $vv [list ""]
}
}
}
proc tixBalloon::BindOneWidget {w client subwidget} {
upvar #0 $w data
if {![winfo exists $subwidget]} {
return
}
set class [winfo class $subwidget]
bind TixBalloon$client <Any-Enter> "tixBalloon::Enter $w $client"
bind TixBalloon$client <Destroy> "tixBalloon::ClientDestroy $w $client"
tixAppendBindTag $client TixBalloon$client
}
#----------------------------------------------------------------------
# Mask window handlng
#----------------------------------------------------------------------
# We need a "mask" window to put all over the client widget so that we can
# find out when the user presses the mouse buttons
#
# This is the most complicated code in all of Tix. If you don't understand
# is going on, don't touch it.
#
bind TixBalloon <Leave> [concat tixBalloon::Leave %W $btn_fields]
bind TixBalloon <Visibility> "raise %W"
# Since the mask window overlays the client widget, it gets all the mouse
# events of the client widget. We need to capture these events and resend
# them to the client widget.
#
proc tixBalloon::InterceptMouseEvents {w mask client} {
global btn_fields
if {![winfo exists $client]} {
return
}
foreach tag [bindtags $client] {
foreach event [bind $tag] {
if [regexp {([1-3]>$)} $event] {
# This is a button event
bind $mask $event \
[concat tixBalloon::GenerateEvent \
$w $client $event $btn_fields]
}
}
}
# We want this for all widgets:
# pressing any mouse button and the
# balloon goes away
bind $mask <1> \
[concat tixBalloon::GenerateEvent $w $client <1> $btn_fields]
bind $mask <2> \
[concat tixBalloon::GenerateEvent $w $client <2> $btn_fields]
bind $mask <3> \
[concat tixBalloon::GenerateEvent $w $client <3> $btn_fields]
}
proc tixBalloon::ReleaseGrab {w client} {
upvar #0 $w data
global tkPriv
catch {
if {$data(grabbed) != {}} {
grab release $client
}
unset data(grabbed)
}
}
proc tixBalloon::SetGrab {w client event} {
upvar #0 $w data
if {[grab current $w] != {}} {
return
}
if [string match "*1*" $event] {
set btn 1
} elseif [string match "*2*" $event] {
set btn 2
} elseif [string match "*3*" $event] {
set btn 3
}
if {[winfo class $client] == "Menubutton"} {
# No need to grab, it will take care of itself
#
set data(grabbed) {}
} else {
puts grabbed
set data(grabbed) $client
grab -global $client
}
bind $client <ButtonRelease-$btn> \
"tixBalloon::ReleaseGrab $w $client"
}
# When this function is called, we have intercepted a mouse event
# for the client widget. Let's send it to the client. But before
# that we have to substitute all the % stuff in the commands.
#
#
proc tixBalloon::GenerateEvent [concat w defClient event $btn_fields] {
upvar #0 $w data
global btn_fields
tixBalloon::Popdown $w
tixDeleteBindTag $data(curWidget) InterceptLeave
set client [winfo containing [set %X] [set %Y]]
set leave 0
if {$client == {}} {
set client $defClient
set leave 1
}
if {$event == "<Leave>"} {
set client $defClient
}
if {$event != "<Leave>"} {
if {$leave} {
global btn_fields
set args {}
foreach f $btn_fields {
lappend args [set $f]
}
eval tixBalloon::GenerateEvent $w $data(curWidget) <Leave> $args
} else {
tixBalloon::SetGrab $w $data(curWidget) $event
}
}
set %W $client
foreach tag [bindtags $client] {
set command [bind $tag $event]
if {$command == {}} {
continue
}
foreach f $btn_fields {
regsub -all $f $command [set $f] command
}
uplevel #0 eval [list $command]
puts $command
}
if {$event != "<Leave>"} {
set data(fakeEnter) 1
set data(fakeLeave) 1
}
}
proc tixBalloon::GetMask {w client} {
global btn_fields
if {![winfo exists $client]} {
## Something insane has happened!
set tp .
} else {
set tp [winfo toplevel $client]
}
if {$tp == "."} {
set tp ""
}
set mask $tp.tixInt:bal
if {![winfo exists $mask]} {
tixInputOnly $mask
bind $mask <Leave> [concat tixBalloon::Leave $w $btn_fields]
}
tixBalloon::InterceptMouseEvents $w $mask $client
return $mask
}
#----------------------------------------------------------------------
# PublicMethods:
#----------------------------------------------------------------------
# %% if balloon is already popped-up for this client, change mesage
#
proc tixBalloon::bind {w client args} {
upvar #0 $w data
if [info exists data(m:$client)] {
set alreadyBound 1
} else {
set alreadyBound 0
}
set opt(-balloonmsg) {}
set opt(-statusmsg) {}
set opt(-msg) {}
tixHandleOptions opt {-balloonmsg -msg -statusmsg} $args
if {$opt(-balloonmsg) != {}} {
set data(m:$client) $opt(-balloonmsg)
} else {
set data(m:$client) $opt(-msg)
}
if {$opt(-statusmsg) != {}} {
set data(s:$client) $opt(-statusmsg)
} else {
set data(s:$client) $opt(-msg)
}
# Set up the bindings of the widget, in which the balloon should appear
#
tixBalloon::BindOneWidget $w $client $client
}
proc tixBalloon::unbind {w client} {
upvar #0 $w data
if [info exists data(m:$client)] {
catch {unset data(m:$client)}
catch {unset data(s:$client)}
if [winfo exists $client] {
catch {tixDeleteBindTag $client TixBalloon$client}
}
}
}